﻿using System;
using System.Collections;

using Storm.TextEditor.Editor;

namespace Storm.TextEditor.Parser.Objects.Collections
{
	/// <summary>
	/// Represents a list of Pattern.
	/// </summary>
	public sealed class PatternList
		: IEnumerable
	{
		#region Fields

		private PatternCollection patterns = new PatternCollection();
		private PatternCollection complexPatterns = new PatternCollection();
		private TextStyle         style           = new TextStyle();

		private Hashtable simplePatterns      = new Hashtable();
		private Hashtable simplePatterns1Char = new Hashtable();
		private Hashtable simplePatterns2Char = new Hashtable();

		private bool   caseSensitive = false;
		private bool   normalizeCase = false;
		private string name          = "";

		private PatternListList parent      = null;
		private Block           parentBlock = null;

		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the Patterns of the PatternList.
		/// </summary>
		public PatternCollection Patterns
		{
			get { return patterns; }
			set { patterns = value; }
		}

		/// <summary>
		/// Gets or sets the complex Patterns of the PatternList.
		/// </summary>
		public PatternCollection ComplexPatterns
		{
			get { return complexPatterns; }
			set { complexPatterns = value; }
		}

		/// <summary>
		/// Gets or sets the TextStyle of the PatternList.
		/// </summary>
		public TextStyle Style
		{
			get { return style; }
			set { style = value; }
		}

		/// <summary>
		/// Gets or sets the simple Patterns of the PatternList.
		/// </summary>
		public Hashtable SimplePatterns
		{
			get { return simplePatterns; }
			set { simplePatterns = value; }
		}

		/// <summary>
		/// Gets or sets the simple Patterns with 1 char of the PatternList.
		/// </summary>
		public Hashtable SimplePatterns1Char
		{
			get { return simplePatterns1Char; }
			set { simplePatterns1Char = value; }
		}

		/// <summary>
		/// Gets or sets the simple Patterns with 2 chars of the PatternList.
		/// </summary>
		public Hashtable SimplePatterns2Char
		{
			get { return simplePatterns2Char; }
			set { simplePatterns2Char = value; }
		}

		/// <summary>
		/// Gets or sets whether the PatternList is case sensitive.
		/// </summary>
		public bool CaseSensitive
		{
			get { return caseSensitive; }
			set { caseSensitive = value; }
		}

		/// <summary>
		/// Gets or sets whether the PatternList should normalize case.
		/// </summary>
		public bool NormalizeCase
		{
			get { return normalizeCase; }
			set { normalizeCase = value; }
		}

		/// <summary>
		/// Gets or sets the name of the PatternList.
		/// </summary>
		public string Name
		{
			get { return name;  }
			set { name = value; }
		}

		/// <summary>
		/// Gets or sets the parent PatternListList of the PatternList.
		/// </summary>
		public PatternListList Parent
		{
			get { return parent; }
			set { parent = value; }
		}

		/// <summary>
		/// Gets or sets the parent Block of the PatternList.
		/// </summary>
		public Block ParentBlock
		{
			get { return parentBlock; }
			set { parentBlock = value; }
		}

		#endregion

		#region Methods

		#region Public

		/// <summary>
		/// Returns the IEnumerator of the PatternList.
		/// </summary>
		/// <returns>The IEnumerator of the PatternList.</returns>
		public IEnumerator GetEnumerator()
		{
			return patterns.GetEnumerator();
		}

		/// <summary>
		/// Adds the given Pattern to the PatternList.
		/// </summary>
		/// <param name="Pattern">Pattern to add.</param>
		/// <returns>The added Pattern.</returns>
		public Pattern Add(Pattern pattern)
		{
			if (parent != null && parent.Parent != null && parent.Parent.Parent != null)
			{
				pattern.Separators = parent.Parent.Parent.Separators;
				parent.Parent.Parent.ChangeVersion();
			}

			if (pattern.IsComplex == false && pattern.ContainsSeparator == false)
			{
				string newPatternString = "";
				if (pattern.StringPattern.Length >= 2)
					newPatternString = pattern.StringPattern.Substring(0, 2);
				else
					newPatternString = pattern.StringPattern.Substring(0, 1) + " ";

				newPatternString = newPatternString.ToLower();
				if (pattern.StringPattern.Length == 1)
					simplePatterns1Char[pattern.StringPattern] = pattern;
				else
				{
					if (simplePatterns2Char[newPatternString] == null)
						simplePatterns2Char[newPatternString] = new PatternCollection();

					PatternCollection ar = (PatternCollection)simplePatterns2Char[newPatternString];
					ar.Add(pattern);
				}

				if (caseSensitive == true)
					simplePatterns[pattern.LowerStringPattern] = pattern;
				else
					simplePatterns[pattern.StringPattern] = pattern;
			}
			else
				complexPatterns.Add(pattern);

			patterns.Add(pattern);
			if (pattern.Parent == null)
				pattern.Parent = this;
			else
				throw (new Exception("Pattern already assigned to another PatternList"));

			return pattern;
		}

		/// <summary>
		/// Clears the PatternList,
		/// </summary>
		public void Clear()
		{
			patterns.Clear();
		}

		#endregion

		#endregion

		/// <summary>
		/// Initializes a new instance of PatternList.
		/// </summary>
		public PatternList()
		{
			simplePatterns = new Hashtable(StringComparer.OrdinalIgnoreCase);
		}
	}
}
